CC := gcc

# 清理（第一个目标，默认选项）
# 最后清屏
# 如何反选，处理.c .h .md makefile 全部删除？
# ls | grep -v -E "\.(c|h|md)|makefile" | xargs rm -rf
# ——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
# ls |
# 列出所有文件和文件夹
# grep -v -E "\.(c|h|md)|^makefile$$" |
# 使用扩展正则表达式，选中所有以.c .h .md结尾 或者 全名makefile 的文件 **反选**
# xargs rm -rf
# 将标准输入，转换为命令行输入，传递给rm
# -rf同时删除文件和文件夹
# ——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
.PHNOY:clear
clear:
# rm -f *.i *.s *.o *.txt main a.out
	ls | grep -v -E "\.(c|h|md)|^makefile$$" | xargs rm -rf





# 编译运行
main: main.c hello_world.h hello_world.c
	$(CC) main.c hello_world.c -o $@
	./$@









main.i:main.c hello_world.h
	$(CC) -E $< -o $@

# 预处理
# 1.宏替换
# 2.文件包含
# 3.条件编译
# 4.注释移除
.PHNOY:preprocess
preprocess:main.i
	code $^







main.s:main.c hello_world.h
	$(CC) -S $< -o $@

# 编译
# 汇编代码、分段
.PHNOY:compile
compile:main.s
	code $^











# -o可以省略，默认生成同名目标文件
main.o:main.c hello_world.h
	$(CC) -c $<

# 汇编
# 机器码、分节
# 1.文件格式
# 2.text，代码
# 3.comment，编译器版本信息
# 4.note.gnu.property，GNU特定的属性
# 5.eh_frame，异常处理

# −s
# −−full−contents
# ——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
# Display the full contents of any sections requested. By default all non-empty sections are displayed.
# 显示所请求的任何部分的全部内容。默认情况下，将显示所有非空部分。
# ——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
.PHNOY:assembly
assembly:main.o
	objdump -s $^
	rm -f main.o

.PHNOY:assembly_file
assembly_file:main.o
	objdump -s $^ > "objdump -s $^.txt"
	code "objdump -s $^.txt"





# 这是 .c -> .o 的默认命令（同名）
# gcc    -c -o hello_world.o hello_world.c
hello_world.o:hello_world.c
	$(CC) -c hello_world.c

# 获得可执行文件，查看更多节
# −h
# −−section−headers
# −−headers
# ——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
# Display summary information from the section headers of the object file.
# 显示来自对象文件的节头的摘要信息。
# 。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。
# File segments may be relocated to nonstandard addresses, for example by using the −Ttext, −Tdata,
# or −Tbss options  to ld. 
# 文件段可能会被重新定位到非标准地址，例如使用- Ttext、- Tdata或- Tbss选项ld。
# 。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。
#							However,  some  object  file  formats,  such  as  a.out,  do  not  store  the  starting
# address  of  the  file  segments. 
# 							但是，某些object文件格式（如a.out）不存储文件段的起始地址。
# 。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。
# 									In those  situations,  although ld relocates  the  sections  correctly, using
# objdump  −h to  list  the  file  section  headers  cannot  show t he  correct  addresses. 
# 									在这些情况下，尽管ld正确地重新定位了节，但使用objdump−h列出文件节头不能显示正确的地址。
# 。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。
# 																							Instead,  it  shows  the
# usual addresses, which are implicit for the target.
#																							相反，它显示了通常的地址，
# 这些地址对于目标来说是隐式的。
# ——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
# Note,  in  some  cases  it  is  possible  for  a  section  to  have  both  the READONLY and  the NOREAD
# attributes  set. 
# 注意，在某些情况下，一个节可能同时设置了READONLY和NOREAD属性。
# 。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。
# 					In  such  cases  the NOREAD attribute  takes  precedence,  but objdump will  report  both
# since the exact setting of the flag bits might be important.
# 					在这种情况下，NOREAD属性优先，但objdump将同时报告这两个属性，因为标志位的确切设置可能很重要。
# ——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
# 这些额外段的作用是什么？各属性？
.PHNOY:more_section
more_section:main.o hello_world.o
	$(CC) $^ -o main
	objdump -h main
	rm -f main main.o hello_world.o

.PHNOY:more_section_file
more_section_file:main
	objdump -h main > "objdump -h main.txt"
	code "objdump -h main.txt"










# 反汇编

# −d
# −−disassemble
# −−disassemble=symbol
# ——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
# Display  the  assembler  mnemonics  for  the  machine  instructions  from  the  input  file.
# 显示输入文件中机器指令的汇编助记符。
# 。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。
# This  option  only disassembles  those  sections  which  are  expected  to  contain  instructions.
# 这个选项只反汇编那些预期包含指令的部分。
# 。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。
# If  the  optional symbol argument  is  given,  then  display  the  assembler  mnemonics  starting  at symbol.
# 如果给出了可选的symbol参数，则显示从symbol开始的汇编助记符。
# 。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。
# If symbol is  a  function name  then  disassembly  will  stop  at  the  end  of  the  function,  otherwise  it  will
# stop  when  the  next symbol is encountered.
# 如果symbol是函数名，那么反汇编将在函数结束时停止，否则它将在遇到下一个符号时停止。
# 。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。
# If there are no matches for symbol then nothing will be displayed.
# 如果符号没有匹配，那么将不显示任何内容。
# ——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
# Note if the −−dwarf=follow−links option is enabled then any s ymbol tables in linked debug info files will be read in
# and used when disassembling.
# 注意，如果启用了- - dwarf=follow - links选项，那么链接的调试信息文件中的任何s符号表将被读入并在反汇编时使用。
# ——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
.PHNOY:disassembly
disassembly:main.o
	objdump -d $^
	rm -f main.o

.PHNOY:disassembly_file
disassembly_file:main.o
	objdump -d $^ > "objdump -d $^.txt"
	code "objdump -d $^.txt"





# 只反汇编一个函数
disassemble_function:main
	objdump --disassemble=hello_world main

# 少一个横线，明明不正确，为什么可以正常输出
	# objdump -disassemble=hello_world main
# -di 看做 -d -i 实际是-i info起作用
# −i
# −−info
# ——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
# Display a list showing all architectures and object formats available for specification with −b or −m.
# 显示带有- b或- m的规格的所有体系结构和对象格式的列表。
# ——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————












# 链接
.PHNOY:link
link:main.o hello_world.o
	$(CC) $^ -o main
	./main
# rm -f main
	make clear


# 静态链接 -static
# 动态链接 非静态链接，默认值是动态链接
.PHNOY:static_link
static_link:main.o hello_world.o
	clear
	gcc -static $^ -o main_static
	gcc $^ -o main_dynamic
	clear
	ls -alh | grep main_
	make -s clear

# -s, --silent, --quiet
# Silent operation; do not print the commands as they are executed.
# 沉默的操作;不要在执行命令时打印命令。


# 生成动态库
# -fPIC 位置无关代码（Position Independent Code）
# -shared 共享库
# 按照惯例，Linux下的共享库名称以lib开头，扩展名为.so（表示共享对象）。
# ——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————	
# -fpic
# Generate position-independent code (PIC) suitable for use in a shared library, if supported for the target machine.
# 生成适合在共享库中使用的位置无关代码（PIC），如果目标机器支持的话。

# Such code accesses all constant addresses through a global offset table (GOT).
# 这样的代码通过一个全局偏移表（GOT）访问所有的常量地址。

# The dynamic loader resolves the GOT entries when the program starts (the dynamic loader is not part of GCC;
# 动态加载器在程序启动时解析GOT条目(动态加载器不是GCC的一部分；

# it is part of the operating system).
# 它是操作系统的一部分)。

# If the GOT size for the linked executable exceeds a machine-specific maximum size, you get an error message from the linker indicating that -fpic does not work;
# 如果链接的可执行文件的get大小超过了特定于机器的最大大小，您将从链接器获得一条错误消息，表明-fpic不起作用；

# 在这种情况下，使用-fPIC重新编译。
# in that case, recompile with -fPIC instead.

# (These maximums are 8k on the SPARC, 28k on AArch64 and 32k on the m68k and RS/6000.
# (这些最大值在SPARC上是8k，在AArch64上是28k，在m68k和RS/6000上是32k。

# The x86 has no such limit.)
# x86没有这样的限制。)

# Position-independent code requires special support, and therefore works only on certain machines.  For the x86, GCC supports PIC for System V
# but not for the Sun 386i.  Code generated for the IBM RS/6000 is always position-independent.
#
# When this flag is set, the macros "__pic__" and "__PIC__" are defined to 1.
# ——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
# -fPIC
# If supported for the target machine, emit position-independent code, suitable for dynamic linking and avoiding any limit on the size of the
# global offset table.  This option makes a difference on AArch64, m68k, PowerPC and SPARC.
#
# Position-independent code requires special support, and therefore works only on certain machines.
#
# When this flag is set, the macros "__pic__" and "__PIC__" are defined to 2.
# ——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
# -shared
# Produce a shared object which can then be linked with other objects to form an executable.  Not all systems support this option.  For
# predictable results, you must also specify the same set of options used for compilation (-fpic, -fPIC, or model suboptions) when you specify
# this linker option.[1]
# ——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
libhello_world.so:hello_world.o
	$(CC) -fPIC -shared $^ -o $@

# 使用动态链接库
# -L 指定库文件搜索路径
# -lhello 指定库名称
# 根据约定，链接器会搜索名为libhello.so（动态库）或libhello.a（静态库）的文件来链接。
# 链接器会根据-L选项指定的路径列表查找这个库。
# LD_LIBRARY_PATH=./ ./main
# 指定库加载路径，运行程序
# Linux的默认动态链接库文件夹是/lib 和/usr/lib
# glibc的动态库和静态库分别位于/usr/lib/x86_64-linux-gnu/目录下的libc.so和libc.a文件中。
custom_dynamic_link:main.o libhello_world.so
	$(CC) main.o -L./ -lhello_world -o main
	LD_LIBRARY_PATH=./ ./main
	make clear
